1 /**
2  * License:
3  *              Copyright Devisualization (Richard Andrew Cattermole) 2014 - 2017.
4  *     Distributed under the Boost Software License, Version 1.0.
5  *        (See accompanying file LICENSE_1_0.txt or copy at
6  *              http://www.boost.org/LICENSE_1_0.txt)
7  */
8 module devisualization.util.core.text;
9 import std..string : indexOf, toUpper, toLower;
10 import std.traits : isSomeString;
11 
12 /**
13  * Replaces some text in a string.
14  * 
15  * Params:
16  * 		text			=	The old text to replace from
17  * 		oldText			=	The text to remove
18  * 		newText			=	The text to replace oldText with
19  * 		caseSensitive	=	Does 'A' and 'a' the same character? Default: true
20  * 		first			=	Stop after the first instance of oldText? Default: false
21  * 
22  * Returns:
23  * 		The text that has been replaced
24  */
25 deprecated("Too memory expensive, requires a rewrite.")
26 T replace(T)(T text, T oldText, T newText, bool caseSensitive = true, bool first = false) pure if (isSomeString!T) {
27 	T ret;
28 	T tempData;
29 	bool stop;
30 	foreach(dchar c; text) {
31 		if (tempData.length > oldText.length && !stop) {
32 			ret ~= tempData;
33 			tempData.length = 0;
34 		}
35 		if (((oldText[0 .. tempData.length] != tempData && caseSensitive) || (oldText[0 .. tempData.length].toLower() != tempData.toLower() && !caseSensitive)) && !stop) {
36 			ret ~= tempData;
37 			tempData.length = 0;
38 		}
39 		tempData ~= c;
40 		if (((tempData == oldText && caseSensitive) || (tempData.toLower() == oldText.toLower() && !caseSensitive)) && !stop) {
41 			ret ~= newText;
42 			tempData.length = 0;
43 			stop = first;
44 		}
45 	}
46 	if (tempData != T.init) {
47 		ret ~= tempData;	
48 	}
49 	return ret;
50 }
51 
52 unittest {
53 	string test = "Hello World!";
54 	test = test.replace("Hello", "Hi");
55 	assert(test == "Hi World!");
56 	
57 	assert(replace("Hello World!", "o", "a") == "Hella Warld!");
58 	assert(replace("Hello World!", "!", "#") == "Hello World#");
59 }
60 
61 /**
62  * Split a string by a delimater
63  * 
64  * Params:
65  * 		text		=	The text to split from
66  * 		delimater	=	The text to split by
67  * 
68  * Returns:
69  * 		An array of text that has been split
70  */
71 deprecated("Use std.algorithm.iteration : splitter instead.")
72 pure T[] split(T)(T text, T delimater) if (isSomeString!T) {
73 	T[] ret;
74 	ptrdiff_t i;
75 	while((i = text.indexOf(delimater)) >= 0) {
76 		ret ~= text[0 .. i];
77 		text = text[i + delimater.length .. $];
78 	}
79 	if (text.length > 0) {
80 		ret ~= text;	
81 	}
82 	return ret;
83 }
84 
85 unittest {
86 	string test = "abcd|efgh|ijkl";
87 	assert(test.split("|") == ["abcd", "efgh", "ijkl"]);
88 	string test2 = "abcd||efgh||ijkl";
89 	assert(test2.split("||") == ["abcd", "efgh", "ijkl"]);
90 }
91 
92 /**
93  * Multiplies a string by itself and concactenates it onto the resulting string
94  *
95  * Similar to how Python's string multiplication works.
96  *
97  * Params:
98  * 		text	=	The text to multiply
99  * 		count	=	How many times to multiply it
100  *
101  * Returns:
102  * 		The multiplied string
103  */
104 T multiply(T)(T text, size_t count) pure @safe nothrow if (isSomeString!T) {
105 	alias U = typeof(cast()T.init[0]);
106 	U[] ret;
107 	ret.length = text.length * count;
108 
109 	size_t j;
110 	foreach(i; 0 .. count) {
111 		ret[j .. j + text.length] = text[];
112 		j += text.length;
113 	}
114 
115 	return ret;
116 }
117 
118 unittest {
119 	assert(" ".multiply(3) == "   ");
120 	assert("hello ".multiply(2) == "hello hello ");
121 	assert("boo".multiply(1) == "boo");
122 	assert("huh".multiply(0) == "");
123 }
124 
125 /**
126  * Gets a string which has been indented to x spaces.
127  * Uses four spaces, not tabs.
128  *
129  * Params:
130  * 		count	=	How many times to indent it
131  *
132  * Returns:
133  * 		The indented string
134  */
135 string getSpaceIndent(size_t count) pure @safe nothrow {
136 	return "    ".multiply(count);
137 }